﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class MagicView : MonoBehaviour {
    public GameObject m_prefab_cube;
    [Range(1, 6)]//7阶魔方顶角转到时会漏出来
    public int m_magic_n = 3;
    public float m_maigc_with = 4;
    private GameObject _magic;

    private List<GameObject> _cubes = new List<GameObject>();

    private GameObject _hit_cube;
    private Vector3 _hit_cube_positon;
    private Vector3 _hit_normal;
    private Vector3 _hit_start;
    private Vector3 _hit_run;
    private Vector3 _hit_cross;

    private bool _is_rotate = false;
    private float _rotate_time = 0;
    public float m_rotate_speed = 100;
    private Vector3 _rotate_direction;
    private GameObject _roller = null;
    private Vector3[] _enum_directions = {
        Vector3.right,Vector3.left,Vector3.up,Vector3.down,Vector3.forward,Vector3.back
    };

    private bool _test = false;
    private GameObject _test_cube_1;
    private GameObject _test_cube_2;
    // Use this for initialization
    void Start () {
        if(_test)
        {
            _test_cube_1 = GameObject.Instantiate(m_prefab_cube);
            _test_cube_1.transform.position = new Vector3(3, 0, 0);
            _test_cube_2 = GameObject.Instantiate(m_prefab_cube);
            _test_cube_2.transform.position = new Vector3(1, 0, 0);
            StartCoroutine(_TestCoroutineFunc());

            return;
        }
        

        InitMagic();
	}

    IEnumerator _TestCoroutineFunc()
    {

        float turn_time = 3;
        float now_time = turn_time;
        while(true)
        {
            var delta_time = Time.deltaTime;
            var degree = delta_time / turn_time * 90;
            now_time -= Time.deltaTime;
            if (now_time > 0)
            {
                _test_cube_1.transform.Rotate(degree, 0, 0);
                _test_cube_2.transform.Rotate(0, degree, 0);
            }
            else if(now_time > -turn_time)
            {
                _test_cube_2.transform.Rotate(degree, 0, 0);
                _test_cube_1.transform.Rotate(0, degree, 0);
            }
            else
            {
                now_time = turn_time;
                _test_cube_2.transform.rotation = Quaternion.identity;
                _test_cube_1.transform.rotation = Quaternion.identity;
            }
            yield return null;
        }
    }

    // 初始化魔方
    void InitMagic()
    {
        // 转动轴
        _roller = new GameObject("roller");
        _roller.transform.SetParent(transform, false);

        _magic = new GameObject("magic");
        _magic.transform.SetParent(transform, false);

        // 生成N*N*N魔方矩阵
        float cube_size = m_maigc_with / m_magic_n;
        var center_x = (m_magic_n - 1) * cube_size / 2;
        var center = new Vector3(center_x, center_x, center_x);
        for (int i = 0; i < m_magic_n; ++i)
        {
            for (int j = 0; j < m_magic_n; ++j)
            {
                for (int k = 0; k < m_magic_n; ++k)
                {
                    // 可做优化如果不是边沿的去掉
                    var cube = GameObject.Instantiate(m_prefab_cube);
                    cube.transform.SetParent(_magic.transform, false);
                    cube.transform.localScale = Vector3.one * cube_size;
                    cube.transform.localPosition = (new Vector3(i, j, k)) * cube_size - center;
                    _cubes.Add(cube);
                }
            }
        }

    }

    // 在Scene中画出发射线、反射线、法线、cross线
    void DrawRayLines(Ray ray,RaycastHit hit)
    {
        Debug.DrawLine(ray.origin, hit.point, Color.red);
        Debug.DrawRay(hit.point, hit.normal * 10, Color.green);
        var reflect_direction = ray.direction + Vector3.Dot(ray.direction, hit.normal) * -2 * hit.normal;
        Debug.DrawRay(hit.point, reflect_direction * hit.distance, Color.magenta);
        Debug.DrawRay(hit.point, Vector3.Cross(ray.direction, hit.normal).normalized * 10, Color.blue);
    }

    private bool _mode_camera = false;
	
	// Update is called once per frame
	void Update () {
        if (_test)
        {
            return;
        }

        // 转动
        if (_is_rotate)
        {
            RotateUpdate();
            return;
        }

        if(Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray.origin, ray.direction, out hit))
            {
                _hit_cube = hit.transform.gameObject;
                _hit_cube_positon = hit.transform.localPosition;
                _hit_normal = hit.normal;
                _hit_start = hit.point;

                DrawRayLines(ray, hit);
                _mode_camera = false;
            }
            else
            {
                // 点到空白处转动摄像机
                _mode_camera = true;
            }
        }

        if (Input.GetMouseButtonUp(0))
        {
            _mode_camera = false;
            _hit_cube = null;
            return;
        }

        if (_mode_camera)
        {
            if (Input.GetMouseButton(0))
            {
                float h = -10 * Input.GetAxis("Mouse X");
                float v = 10 * Input.GetAxis("Mouse Y");
                //transform.Rotate(v, h, 0, Space.World);
                transform.Rotate(Camera.main.transform.right, v, Space.World);
                transform.Rotate(Camera.main.transform.up, h, Space.World);
                //transform.Rotate(Camera.main.transform.right, v, Space.World);
                return;
            }
        }
        // 点中物体（魔方）
        if (Input.GetMouseButton(0) && _hit_cube == null && _is_rotate == false)
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if(Physics.Raycast(ray.origin,ray.direction,out hit))
            {
                _hit_cube = hit.transform.gameObject;
                _hit_cube_positon = hit.transform.localPosition;
                _hit_normal = hit.normal;
                _hit_start = hit.point;

                DrawRayLines(ray, hit);
            }
            else
            {
                // 点到空白处转动摄像机
            }
        }
        // 拖动
        if(Input.GetMouseButton(0) && _hit_cube != null && _is_rotate == false)
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray.origin, ray.direction, out hit))
            {
                _hit_run = hit.point - _hit_start;
                Debug.DrawLine(_hit_start, hit.point, Color.red);
                DrawRayLines(ray, hit);
                if (_hit_run.sqrMagnitude > 1)
                {
                    _hit_cross = Vector3.Cross(_hit_normal, _hit_run).normalized;
                    _rotate_direction = GetRotateDirection(_hit_cross);
                    RotateStart(_rotate_direction);
                    _hit_cube = null;
                }
            }
        }
    }

    Vector3 GetRotateDirection(Vector3 cross)
    {
        Vector3[] normal_dirs = {
            Vector3.right,Vector3.left,
            Vector3.up,Vector3.down,
            Vector3.forward,Vector3.back,
        };
        Vector3[] dirs = {
            transform.right,-transform.right,
            transform.up,-transform.up,
            transform.forward,-transform.forward,
        };

        float dot = 0,tmp = 0;
        Vector3 ret = new Vector3(0, 0, 0);

        for (var i = 0; i < 6; i++)
        {
            tmp = Vector3.Dot(dirs[i], cross);
            if (tmp > dot)
            {
                dot = tmp;
                ret = normal_dirs[i];
            }
        }
        return ret;
    }

    void RotateStart(Vector3 dir)
    {
        // 把要转动的cube移动到转动轴上
        // 判断方法：
        // 和被点到的cube在dir的方向上的位置投影距离为0的将转动
        foreach(var cube in _cubes)
        {
            Vector3 vec = cube.transform.localPosition - _hit_cube_positon;
            if(Mathf.Abs(Vector3.Dot(vec, dir)) < 0.1)
            {
                cube.transform.parent = _roller.transform;
            }
        }
        _is_rotate = true;
        _rotate_time = 0;
    }

    void RotateUpdate()
    {
        _rotate_time += Time.deltaTime * m_rotate_speed / 90;
        Vector3 rotate = _rotate_direction * Mathf.Clamp01(_rotate_time) * 90;
        _roller.transform.localEulerAngles = rotate;
        if (_rotate_time >= 1)
        {
            _rotate_time = 0;
            RotateEnd();
            _roller.transform.localRotation = Quaternion.identity;
        }
    }

    void RotateEnd()
    {
        foreach (var cube in _cubes)
        {
            cube.transform.parent = _magic.transform;
        }
        _is_rotate = false;
    }
}
